#ifndef __COTASK_H__
#define __COTASK_H__
/*************************************Include********************************************/
#include <stdint.h>
#include <stdio.h>
/**********************************Macro Setting****************************************/
// <<< Use Configuration Wizard in Context Menu >>>

// <h> CoTask configurations and settings

// <o> Define FREQ_OF_TICK_COLCK <10-2000:1>
// <i> Default: 1000, The Frequency of the timer which support the tick.
#define FREQ_OF_TICK_COLCK          1000

// <q> Enable Semaphore Support
// <i> Default: 1, Enable or disable semaphore support for CoTask
#define COTASK_SEMAPHORE_ENABLE     1

// <q> Enable Utilization Monitoring
// <i> Default: 1, Enable or disable task utilization monitoring
#define COTASK_UTILIZATION_ENABLE   0

// </h>

// <<< end of configuration section >>>



/*************************************TypeDefs********************************************/
typedef enum {
    E_DELAY_STATE_FINISH = 0x00, // 延时完成状态
    E_DELAY_STATE,          // 单纯延时状态
#if(COTASK_SEMAPHORE_ENABLE==1)
E_WAIT_SEM_DELAY_STATE, // 等待信号量的延时  
E_WAIT_SEM_DELAY_TIMEOUT, // 等待信号量的延时超时  
#endif
} EDelayState;

typedef struct _cotask CoTask;
typedef uint8_t (*CoTaskFun)(CoTask* p_cotask); // Task function type
#if(COTASK_SEMAPHORE_ENABLE==1)
typedef uint8_t CoTaskSemaphore; //cotask的信号量，最多支持释放256个 
#endif
struct _cotask
{
    struct _cotask *next; // Pointer to the next task in the linked list
#if(COTASK_SEMAPHORE_ENABLE==1)
    CoTaskSemaphore* wait_semaphore; // 等待信号量的释放
#endif
    CoTaskFun task_callback; // Task callback function
    uint16_t delay_tick; // delay tick counter
    uint16_t cotask_state; //yeild出去的状态(行号)
    EDelayState delay_flag:8; // Delay flag
};


/*************************************MacroFunction****************************************/
//毫秒到TICK的换算
#define MS2TICK(ms)             ((ms)*(FREQ_OF_TICK_COLCK)/1000)    

//进入每个CoTask调函数域内，需要在进入回调函数中马上调用
#define COTASK_ENTER switch(p_cotask->cotask_state) { case 0:

//退出每个CoTask调函数域内，需要在退出回调函数时调用
#define COTASK_EXIT  } p_cotask->cotask_state = 0; return 1;

//在CoTask中调用，会马上退出，并在tick时刻后重新回到退出地方重新运行
// (当然此时不能有另外的CoTask占用着MCU运行, 如果有CoTask占用着MCU，那只有等待它释放MCU才可以)
#define COTASK_AWIAT_TICK(tick_of_delay) \
    do { \
        p_cotask->cotask_state= __LINE__; \
        p_cotask->delay_flag = E_DELAY_STATE;/*进入延时状态*/ \
        p_cotask->delay_tick = tick_of_delay;/*延时时间，单位 tick*/ \
        return 0; \
        case __LINE__:; \
    } while(0)

#if(COTASK_SEMAPHORE_ENABLE==1)
//在任何地方都能调用，用于释放一个信号量
#define COTASK_RELEASE_SEM(sem)\
    do{ \
        if(sem < 255)sem++; \
    }while(0)

//在CoTask回调函数中调用，等待一个信号量，
//当有信号量释放时，如果此时MCU没有被其他CoTask占用运行，会进入该回调函数，从等待处往后执行
#define COTASK_AWAIT_SEM(sem) \
    do{ \
        p_cotask->cotask_state= __LINE__; \
        p_cotask->wait_semaphore = &sem; \
        return 0; \
        case __LINE__:; \
    }while(0)

//在CoTask回调函数中调用，等待一个信号量，并设置了超时时间
//当有信号量释放时，如果此时MCU没有被其他CoTask占用运行，会进入该回调函数，从等待处往后执行
//即使没有信号量释放，只要过了超时时间，且MCU没有被其他CoTask占用运行，也会进入该回调函数，从等待处往后执行
//在等待该信号量后，可以使用@ COTASK_WAIT_SEM_IS_TIMEOUT 这个宏函数检查是否是等待信号量超时
#define COTASK_AWAIT_SEM_UNTIL(sem, tick_of_delay) \
    do { \
        p_cotask->cotask_state= __LINE__; \
        p_cotask->delay_flag = E_WAIT_SEM_DELAY_STATE;/*进入延时状态*/ \
        p_cotask->wait_semaphore = &(sem); \
        p_cotask->delay_tick = tick_of_delay;/*延时时间，单位 tick*/ \
        return 0; \
        case __LINE__:; \
    } while(0)   

//在CoTask回调函数中调用，检查等待信号量有没有超时
#define COTASK_WAIT_SEM_IS_TIMEOUT(sem) (p_cotask->delay_flag == E_WAIT_SEM_DELAY_TIMEOUT)
#endif


#ifdef __cplusplus
extern "C" {
#endif
/*************************************ExtendFunction****************************************/
uint8_t CoTask_Create(CoTask * ptask, CoTaskFun task_callback);
uint8_t CoTask_Delete(CoTask * ptask);
uint8_t CoTask_Proc(void);
uint8_t CoTask_Tick(void);
#if(COTASK_UTILIZATION_ENABLE==1)
float CoTask_GetUtilization(void);
#endif


/*************************************FunctionImplememnt****************************************/
//由于COTASK实现上不需要提供接口函数，所以，建议直接将这个实现放在中断函数文件中，方便中断函数调用CoTask_Tick()
#ifdef COTASK_IMPLEMENT
//全局静态变量
static CoTask * haedptr = NULL;         //CoTask 列表头指针
#if(COTASK_UTILIZATION_ENABLE==1)
static uint8_t utilization_flag_intask = 0;     //用于粗略计算利用率的flag//在task执行前至1，执行结束后至0
static uint16_t utilization_counter_1s = 0;      //用于粗略计算利用率的counter(用来计时1s钟的counter)
static uint16_t utilization_counter_intask = 0;  //用于粗略计算利用率的counter(用来计时有多少时间在task执行过程中)
static float utilization = 0;                 //用于存储当前的利用率
float CoTask_GetUtilization(void){
    return utilization;
}
#endif
//具体函数实现
uint8_t CoTask_Create(CoTask * ptask, CoTaskFun task_callback)
{
    if (ptask == NULL || task_callback == NULL) {
        return 1; // 返回1表示无效参数
    }
    ptask->delay_flag = E_DELAY_STATE_FINISH;
    ptask->delay_tick = 0;
    ptask->cotask_state = 0;
#if(COTASK_SEMAPHORE_ENABLE==1)
    ptask->wait_semaphore = NULL;
#endif
    ptask->task_callback = task_callback;
    // 头插法
    if (haedptr == NULL) {
        haedptr = ptask; // First task
    } else {
        ptask->next = haedptr;
        haedptr = ptask; // Insert at the head of the list 
    }
    return 0; // Success
}

uint8_t CoTask_Delete(CoTask * ptask){
    if(ptask == NULL){
        return 1; // 返回1表示无效参数
    }
    if(ptask == haedptr){ // If the task to be deleted is the head of
        haedptr = ptask->next; // Move the head to the next task
    } else {
        CoTask* p = haedptr; 
        while(p->next != NULL){
            if(p->next == ptask){ // Find the task to be deleted
                p->next = p->next->next; // Delete the task
                return 0; // Success
            }
            p = p->next;
        }
    }
    return 1; //没有找到ptask,无法删除，返回删除失败
}

uint8_t CoTask_Tick(void)
{
    CoTask *current = haedptr;
    while (current != NULL) {
#if(COTASK_SEMAPHORE_ENABLE==1)
        if (current->delay_flag == E_DELAY_STATE || \
            current->delay_flag == E_WAIT_SEM_DELAY_STATE) {
#else 
        if (current->delay_flag == E_DELAY_STATE){        
#endif
            if(current->delay_tick != 0){ //时间还没有到期的话
                current->delay_tick--;
            }else { //延时时间到期
                if(current->delay_flag == E_DELAY_STATE) //普通延时到期
                    current->delay_flag = E_DELAY_STATE_FINISH; // 标志普通延时完成
#if(COTASK_SEMAPHORE_ENABLE==1)
                else if(current->delay_flag == E_WAIT_SEM_DELAY_STATE) //等待信号量延时到期
                    current->delay_flag = E_WAIT_SEM_DELAY_TIMEOUT; // 标志等待量超时
#endif
            }
        }
        current = current->next; // Move to the next task
    }
#if(COTASK_UTILIZATION_ENABLE==1)
    if(utilization_flag_intask)
        utilization_counter_intask++;
    utilization_counter_1s++;
    if(utilization_counter_1s == MS2TICK(1000)){ //计时达到一秒的话
        utilization = (utilization_counter_intask*1.0)/utilization_counter_1s;
        utilization_counter_intask = 0;
        utilization_counter_1s = 0;
    }
#endif
    return 0; // Success
}

uint8_t CoTask_Proc(void)
{
    CoTask *current = haedptr;
    while (current != NULL) {
#if(COTASK_SEMAPHORE_ENABLE==1)
        if((current->wait_semaphore != NULL && *(current->wait_semaphore) != 0) /*有信号量释放了*/ \
            || current->delay_flag == E_DELAY_STATE_FINISH /*单纯延时完成了*/ \
            || current->delay_flag == E_WAIT_SEM_DELAY_TIMEOUT /*等待信号量超时了*/ ){
            if(current->wait_semaphore != NULL && *(current->wait_semaphore) != 0){ //如果是获取到信号量进入的回调
                (*(current->wait_semaphore))--; //获取一个信号量
                current->delay_flag = E_DELAY_STATE_FINISH;
                current->delay_tick = 0;
                current->wait_semaphore = NULL; //不再获取该信号量
            }
#else 
        if(current->delay_flag == E_DELAY_STATE_FINISH /*单纯延时完成了*/){
#endif
            if (current->task_callback != NULL) {
#if(COTASK_UTILIZATION_ENABLE==1)
                utilization_flag_intask = 1;
#endif
                current->task_callback(current); // Call the task callback function
#if(COTASK_UTILIZATION_ENABLE==1)
                utilization_flag_intask = 0;
#endif
            }
        }
        current = current->next; // Move to the next task
    }
    return 0; // Success
}


#endif



#ifdef __cplusplus
}
#endif

#endif

